package mmc.objects;

import static org.lwjgl.opengl.ARBPointParameters.GL_POINT_SIZE_MAX_ARB;
import static org.lwjgl.opengl.ARBPointParameters.GL_POINT_SIZE_MIN_ARB;
import static org.lwjgl.opengl.ARBPointParameters.glPointParameterfARB;
import static org.lwjgl.opengl.ARBPointSprite.GL_POINT_SPRITE_ARB;
import static org.lwjgl.opengl.GL11.GL_LIGHTING;
import static org.lwjgl.opengl.GL11.GL_POINTS;
import static org.lwjgl.opengl.GL11.GL_TEXTURE;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glColor4f;
import static org.lwjgl.opengl.GL11.glDepthMask;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glPointSize;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glVertex3f;
import mmc.Constants;
import mmc.EngineObject;
import mmc.MovableEngineObject;
import mmc.Settings;
import mmc.physics.PhysicsReactionType;
import mmc.physics.PhysicsType;
import mmc.physics.Position;
import mmc.resource.TextureLoader;
import mmc.server.Scene;
import mmc.server.Server;

@SuppressWarnings("serial")
public class Rocket extends MovableEngineObject{

	public transient static float EXPLOSION_RANGE = 15f;
	public transient static float EXPLOSION_DAMAGE = 500f;
	public transient static float LIFETIME = 30f; 
	private transient double timer = LIFETIME;
	private transient boolean exploded = false;
	
	private static transient int count = 100;
	private transient float[] px;
	private transient float[] py;
	private transient float[] pz;
	private transient float[] pvx;
	private transient float[] pvy;
	private transient float[] pvz;
	
	public Rocket(float x, float y, float z, float vx, float vy, float vz) {
		super(x, y, z, vx, vy, vz);
		physicsType = PhysicsType.MANAGED;
		reactionType = PhysicsReactionType.ABSORB;
		boundingSphere.radius = 0.5f;
		health = 100f;
	}
	
	@Override
	public void initOnClient(mmc.Scene scene){
		px = new float[count];
		py = new float[count];
		pz = new float[count];
		pvy = new float[count];
		pvz = new float[count];
		pvx = new float[count];
		
		for(int i=0;i<count;i++){
			px[i] = super.x;
			py[i] = super.y;
			pz[i] = super.z;
			pvx[i] = -vx + (float)(2*Math.random()-0.1f)*0.2f;
			pvy[i] = -vy + (float)(2*Math.random()-0.1f)*0.2f;
			pvz[i] = -vz + (float)(2*Math.random()-0.1f)*0.2f;
		}
		
		//physics are transient -> not transmitted by server
		physicsType = PhysicsType.MANAGED; //extrapolate between server updates
	}

	@Override
	public void render(EngineObject observer) {
		float size = 10;
		
		glColor4f(1,1,1,1);
		glEnable(GL_TEXTURE);
		glDisable(GL_LIGHTING);
		
		glPointParameterfARB(GL_POINT_SIZE_MIN_ARB, 1e-9f);
        glPointParameterfARB(GL_POINT_SIZE_MAX_ARB, 1e9f);
        glPointParameterfARB(org.lwjgl.opengl.ARBPointParameters.GL_POINT_DISTANCE_ATTENUATION_ARB,1);
        glPointSize(size);
        glEnable(GL_POINT_SPRITE_ARB);
        
        TextureLoader.load("mmc/resource/data/Smoke.png").bind();
        
        glDepthMask(false);
        glBegin(GL_POINTS);
        glTexCoord2f(0.5f, 0.5f);
        for(int i=0;i<count;i++)
        	glVertex3f(px[i],py[i],pz[i]);
        glEnd();
        glDepthMask(true);
        
        glDisable(GL_POINT_SPRITE_ARB);
        glEnable(GL_LIGHTING);
	}

	@Override
	public void update(float dt) {
		//accelerate!
		vx += vx*dt;
		vy += vy*dt;
		vz += vz*dt;
		
		float friction = (float) Math.sqrt(vx*vx+vy*vy*vz*vz);
		friction*=friction;
		friction*=1e-10;
		
		vx *= 1-friction;
		vy *= 1-friction;
		vz *= 1-friction;
		
		//tricky rocket aerodynamics
		vy -= Settings.PHYSICS_GRAVITY*dt*0.8;
		vx += (Math.random()-.5f)*1e3*dt;
		vy += (Math.random()-.5f)*1e3*dt;
		vz += (Math.random()-.5f)*1e3*dt;
		
		if(!Constants.IS_SERVER){
			for(int i=0;i<count;i++){
				px[i] += pvx[i]*dt;
				py[i] += pvy[i]*dt;
				pz[i] += pvz[i]*dt;
				
				if(Math.random()<1e-2){
					px[i] = super.x;
					py[i] = super.y;
					pz[i] = super.z;
					pvx[i] = -vx*0.1f + (float)(2*Math.random()-0.1f)*0.2f;
					pvy[i] = -vy*0.1f + (float)(2*Math.random()-0.1f)*0.2f;
					pvz[i] = -vz*0.1f + (float)(2*Math.random()-0.1f)*0.2f;
				}
			}
		}
	}
	
	@Override
	public boolean copyTo(EngineObject o2) {
		Rocket o = (Rocket)o2;
		o.x = super.x;
		o.y = super.y;
		o.z = super.z;
		o.vx = super.vx;
		o.vy = super.vy;
		o.vz = super.vz;
		o.health = super.health;
		
		return true;
	}
	
	@Override
	public void update(Server server, float dt) {
		update(dt);
		
		timer -= dt;
		if(timer<0)
			explode();
	}
	
	@Override
	public void notifyCellCollission(Position pos) {
		explode();
	}

	@Override
	public void notifyCollission(EngineObject other, Position pos) {
		explode();
	}

	public void explode(){
		if(exploded)
			return;
		
		exploded = true;
		
		Scene scene = Server.instance.getScene();
		scene.removeObject(this);
		scene.doDmgAOE(this,EXPLOSION_RANGE,EXPLOSION_DAMAGE);
	}
}
